#include "allincludes.h"
int OneLine::GetFromFile(fstream &inFile, int newHeadSize,  int newAnalogNum, int newBinsNum, int pos,bool newbIsNormalized, bool newbIsSigma)
{
	//If data format changes, edit here...
	inFile.seekg(pos+4);
	inFile.read((char*)(&iSoftwareVersion), newHeadSize);
	inFile.read((char*)analogData, newAnalogNum*sizeof(float));
	inFile.read((char*)data, newBinsNum*sizeof(float));
	headSize=newHeadSize;
	binsNum=newBinsNum;
	averageTime=(int)(this->lNumberOfShotsPerAverage/this->dFrequencyOfLaser);
	binsLengthX=(int)(dTimeOfBin*C*0.5/7.5+0.5);
	bIsNormalized=newbIsNormalized;
	bIsSigma=newbIsSigma;

	return SUCCEED;
}

//These 2 Write Function are for test only...
int OneLine::WriteDetail(ostream &outStream)
{
	outStream<<"==== "<<year<<" "<<month<<" "<<day<<"   "<<hours<<" "<<minutes<<" "<<seconds<<" "<<millisecond<<" ===="<<endl;
	outStream<<"dTimeOfBin / Freq: "<<dTimeOfBin<<"  "<<dFrequencyOfLaser<<endl;
	outStream<<"NumOfShots / NumOfAnalog: "<<lNumberOfShotsPerAverage<<"  "<<iNumberOfAnalog<<endl;
	outStream<<"Average Time: "<<averageTime<<endl;
	outStream<<"DeadTime Corrected? "<<analogData[4]<<endl;
	outStream<<"Abstract: ";
	for(int i=0; i<20;i++)
	{
		outStream<<data[i]<<"\t";
	}
	outStream<<" ........ "<<endl;
	return SUCCEED;
}
int OneLine::WriteFormat(ostream &outStream)
{
	for(int i=0;i<2000;i++)
	{
		float temp=this->data[i];

		outStream<<temp<<"\n";
	}
	return SUCCEED;
}

////The following Writers are really helpful... 
int OneLine::WriteAtmosProfile(ostream &outStream)
{
	if(!outStream)
	{
		cout<<"Error : Invalid outStream for Atmos Profile..."<<endl;
		return FAILED;
	}
	else
	{
		outStream<<"===This is the Atmos Profile file==="<<endl;
		outStream<<"The data following are index, height(km), temperature(K), pressure(hPa)"<<endl;
		outStream<<"This is different from the input Profile file, which is brief and short... "<<endl;
		outStream<<MAXBINSNUM-FIRSTDATAINDEX+1<<"           "<<endl;
		for(int i=FIRSTDATAINDEX;i<MAXBINSNUM;i++)
		{
			outStream.setf(ios::showpoint);
			outStream<<setw(6)<<i<<setprecision(4)<<setw(10)<<IndexToHeight(i)<<setprecision(4)<<setw(10)<<TProfile[i]<<setprecision(6)<<setw(10)<<PProfile[i]<<endl;
		}
		return SUCCEED;
	}
}
int OneLine::WriteOverlapCoefficient(ostream &outStream)
{
	/*int FIRSTDATAINDEX;
	if(binsLengthX==1) FIRSTDATAINDEX=FIRSTDATAINDEX_7_5M;
	else if(binsLengthX==2) FIRSTDATAINDEX=FIRSTDATAINDEX_15M;
	else {cout<<"Can't handle this resolution!"<<endl;exit(FAILED);}*/

	if(!outStream)
	{
		cout<<"Warning : Invalid outStream for Overlap Coefficient..."<<endl;
		return FAILED;
	}
	else
	{
		cout<<"  Writing data to an Overlap Coefficient file..."<<endl;
		outStream<<"This is an Overlap Coefficient File"<<endl;
		outStream<<"There should be 3 comment lines in the beginning, including this line... "<<endl;
		outStream<<"The data's resolution is "<<7.5*binsLengthX<<" m. Format: Index, Distance(km), Overlap Coefficient"<<endl;
		outStream<<(overlapEndIndex-FIRSTDATAINDEX+1)<<"     "<<binsLengthX<<endl;
		for(int i=FIRSTDATAINDEX;i<=overlapEndIndex&&i<MAXBINSNUM;i++)
		{
			outStream<<setw(6)<<i<<setprecision(6)<<setw(12)<<IndexToDistance(i)<<setprecision(6)<<setw(20)<<overlapCoefficient[i]<<endl;
		}
		return SUCCEED;
	}
}
int OneLine::WriteAfterpulse(string outFileName)
{
	if (outFileName=="")
	{
		outFileName=ini.outputPath+ GetTimeString() +"_"+ GetAverageMinString()+"min.average.aftp.txt";
	}
	ofstream outFile(outFileName.c_str());

	if(!outFile)
	{
		cout<<"Error : Can't create or open file : "<<outFileName<<endl;
		return FAILED;
	}
	else
	{
		cout<<"  Writing data to an afterpulse file..."<<endl;
		outFile<<"This is an Afterpulse File"<<endl;
		outFile<<"There should be 3 comment lines in the beginning, including this line... "<<endl;
		outFile<<"The data's resolution is "<<7.5*binsLengthX<<" m. Format: Index, Distance(km), Afterpulse"<<endl;
		outFile<<afterpulseEndIndex+1<<"     "<<binsLengthX<<endl;
		for(int i=0;i<=afterpulseEndIndex&&i<MAXBINSNUM;i++)
		{
			outFile<<setw(6)<<i<<setprecision(6)<<setw(12)<<IndexToDistance(i)<<setprecision(6)<<setw(20)<<afterpulse[i]<<endl;
		}
		outFile.close();
		return SUCCEED;
	}
}
int OneLine::WriteDataToAfterpulse(string outFileName)
{

	if (outFileName=="")
	{
		outFileName=ini.outputPath+ GetTimeString() +"_"+ GetAverageMinString()+"min.average.aftp.txt";
	}
	ofstream outFile(outFileName.c_str());

	if(!outFile)
	{
		cout<<"Error : Can't create or open file : "<<outFileName<<endl;
		return FAILED;
	}
	else
	{
		cout<<"  Writing data to an afterpulse file..."<<endl;
		outFile<<"This is an Afterpulse File"<<endl;
		outFile<<"There should be 3 comment lines in the beginning, including this line... "<<endl;
		outFile<<"The data's resolution is "<<7.5*binsLengthX<<" m. Format: Index, Distance(km), Afterpulse"<<endl;
		outFile<<binsNum<<"     "<<binsLengthX<<endl;
		for(int i=0;i<binsNum && i<MAXBINSNUM;i++)
		{
			outFile<<setw(6)<<i<<setprecision(6)<<setw(12)<<IndexToDistance(i)<<setprecision(6)<<setw(20)<<data[i]/analogData[ENERGYINDEX]<<endl;
		}
		outFile.close();
		return SUCCEED;
	}
}

int OneLine::WriteAsItIs(string outFileName)
{
	
	if (outFileName=="")
	{
		if(bIsSigma)
			outFileName=ini.outputPath+ GetTimeString() +"_"+ GetAverageMinString()+"min.average.RAW.Extinctn.txt";
		else if(bIsNormalized)
			outFileName=ini.outputPath+ GetTimeString() +"_"+ GetAverageMinString()+"min.average.RAW.normalizeBackScat.txt";
		else
			outFileName=ini.outputPath+ GetTimeString() +"_"+ GetAverageMinString()+"min.average.RAW.BackScat.txt";
	}
	ofstream outFile(outFileName.c_str());

	if(!outFile)
	{
		cout<<"Error : Can't create or open file : "<<outFileName<<endl;
		return (FAILED);
	}
	else
	{
		cout<<"  Writing data to an txt RAW file : "<<outFileName<<endl;
		outFile<<"This is an txt RAW File of ";
		if(bIsSigma)
			outFile<<"SigmaA"<<endl;
		else if(bIsNormalized)
			outFile<<"Normalized BackScatter"<<endl;
		else
			outFile<<"un-Normalized BackScatter"<<endl;
		outFile<<"Maybe there's no need to keep the 3 line comment role in this file..."<<endl;
		outFile<<"The data's resolution is "<<7.5*binsLengthX<<" m. Format: Index, Distance(km), Height(km),  Data"<<endl;
		
		outFile<<setw(4)<<year<<setw(4)<<month<<setw(4)<<day<<setw(8)<<hours<<setw(4)<<minutes<<setw(4)<<seconds<<endl;
		//outStream<<averageTime<<endl;
		outFile<<dFrequencyOfLaser<<endl;
		outFile<<lNumberOfShotsPerAverage<<endl;  //maybe we need to add this num up later..
		outFile<<setprecision(6)<<analogData[ENERGYINDEX]<<endl;
		outFile<<setprecision(6)<<analogData[TEMPDETECTORINDEX]<<setw(16)<<setprecision(6)<<analogData[TEMPBOXINDEX]<<setw(16)<<setprecision(6)<<analogData[TEMPLASERINDEX]<<endl;
		outFile<<setprecision(6)<<analogData[CLOUDBASEHEIGHTINDEX1]<<endl;
		outFile<<setprecision(6)<<analogData[BACKGROUNDINDEX]<<endl;
		outFile<<setprecision(6)<<dTimeOfBin<<endl;        //in seconds...
		outFile<<setprecision(6)<<binsNum*0.0075*binsLengthX<<endl;  //Maxaltitude?
		outFile<<analogData[DEADTIMECORRECTEDINDEX]<<endl;
		outFile<<setw(12)<<binsNum<<endl;

		outFile<<binsNum<<"     "<<binsLengthX<<endl;
		for(int i=0;i<binsNum && i<MAXBINSNUM;i++)
		{
			outFile<<setw(6)<<i<<setprecision(6)<<setw(12)<<IndexToDistance(i)<<setprecision(6)<<setw(12)<<IndexToHeight(i)<<setprecision(6)<<setw(20)<<data[i]<<endl;
		}
		outFile.close();
		return SUCCEED;
	}
}
int OneLine::WriteDataAsLidarPro(ostream &outStream, int recNum, int outputSize, bool outputFloat,bool outputOriginal) 
{
	if(!outStream)
	{
		cout<<"Error : Invalid outStream for LidarPro Image File"<<endl;
		return FAILED;
	}
	outStream<<setw(4)<<year<<setw(4)<<month<<setw(4)<<day<<setw(8)<<hours<<setw(4)<<minutes<<setw(4)<<seconds<<endl;
	//outStream<<averageTime<<endl;
	outStream<<dFrequencyOfLaser<<endl;
	outStream<<lNumberOfShotsPerAverage<<endl;  //maybe we need to add this num up later..
	outStream<<setprecision(6)<<analogData[ENERGYINDEX]<<endl;
	outStream<<setprecision(6)<<analogData[TEMPDETECTORINDEX]<<setw(16)<<setprecision(6)<<analogData[TEMPBOXINDEX]<<setw(16)<<setprecision(6)<<analogData[TEMPLASERINDEX]<<endl;
	outStream<<setprecision(6)<<analogData[CLOUDBASEHEIGHTINDEX1]<<endl;
	outStream<<setprecision(6)<<analogData[BACKGROUNDINDEX]<<endl;
	outStream<<setprecision(6)<<dTimeOfBin<<endl;        //in seconds...
	outStream<<setprecision(6)<<binsNum*0.0075*binsLengthX<<endl;  //Maxaltitude?
	outStream<<analogData[DEADTIMECORRECTEDINDEX]<<endl;
	outStream<<recNum<<setw(12)<<binsNum;
	if(OUTPUTSIZE_IN_IMG_TXT)
		outStream<<setw(12)<<outputSize;
	outStream<<endl;

	int i;
	for(i=0;( i<outputSize && i<binsNum-FIRSTDATAINDEX );i++)
	{
		float temp=data[i+FIRSTDATAINDEX];

		if(!outputOriginal)
		{
			if (!bIsSigma)
			{
				
				if(temp<LOGLOWLIMIT)
					temp=LOGLOWLIMIT;
				temp=(log(temp)+ini.IMG_BACK_PARA_1)*ini.IMG_BACK_PARA_2;  //IMG_PARA_1=4.5, IMG_PARA_2=40;
			}
			else
			{
				//temp /=1000.0;  //km
				if(temp<LOGLOWLIMIT)
					temp=LOGLOWLIMIT;
				temp = (log(temp)+ini.IMG_EXTC_PARA_1)*ini.IMG_EXTC_PARA_2;   //AER_PARA_1=3.1, AER_PARA2=62.5
			}

			if(temp>=255.0)
				temp=255.0;
			if(temp<=0.0)
				temp=0.0;

			if(outputFloat)
				outStream<<setw(8)<<setprecision(4)<<temp/255.0<<" ";
			else
				outStream<<setw(3)<<(int)(temp+0.5)<<" ";
		}
		else
			outStream<<setw(12)<<setprecision(6)<<temp<<" ";

		if((i+1)%20==0)
			outStream<<endl;
	}
	if(i%20!=0)
		outStream<<endl;



	return SUCCEED;

}
int OneLine::WriteSigmaATimeSerie(ostream &outStream,int heightIndex)
{
	if(!bIsSigma)
	{
		cout<<"Error : Can't write backscat data into sigma a serie directly!"<<endl;
		return FAILED;
	}
	if(!outStream)
	{
		cout<<"Error : Invalid outStream for Extinctn Time Serie..."<<endl;
		return FAILED;
	}
	
	outStream<<setw(4)<<year<<setw(4)<<month<<setw(4)<<day<<setw(8)<<hours<<setw(4)<<minutes<<setw(4)<<seconds;
	//outStream<<blahblah... not finished yet...
	outStream<<setw(12)<<setprecision(4)<<data[heightIndex]<<endl;
	
	return SUCCEED;
}
int OneLine::WriteAODTimeSerie(ostream &outStream, int limitIndex)
{
	if(!bIsSigma)
	{
		cout<<"Error : Can't write backscat data into sigma a serie directly!"<<endl;
		return FAILED;
	}
	if(!outStream)
	{
		cout<<"Error : Invalid outStream for AOD Time Serie... "<<endl;
		return FAILED;
	}
	
	float AODunderLimit=GetAOD(limitIndex, ini.sa, ini.lidarConst);

	outStream<<setw(4)<<year<<setw(4)<<month<<setw(4)<<day<<setw(8)<<hours<<setw(4)<<minutes<<setw(4)<<seconds;
	//outStream<<blahblah... not finished yet...
	outStream<<setw(12)<<setprecision(4)<<AODunderLimit<<endl;
	
	return SUCCEED;
}
int OneLine::WriteCloudBottomTimeSerie(ostream &outStream)
{
	if(bIsSigma)
	{
		cout<<"Error : Can't get cloud bottom from sigmaA line"<<endl;
		return FAILED;
	}
	if(!outStream)
	{
		cout<<"Error : Invalid outStream for Cloud Bottom Serie..."<<endl;
		return FAILED;
	}
	int cloudBottomIndex=GetCloudBottomIndex(ini.cloudDetectThreshold, ini.cloudDetectThreshold2, ini.cloudDetectThreshold3);
	float cloudBottomHeight=-999;
	if (cloudBottomIndex>=FIRSTDATAINDEX && cloudBottomIndex<binsNum)
		cloudBottomHeight=IndexToHeight(cloudBottomIndex);


	outStream<<setw(4)<<year<<setw(4)<<month<<setw(4)<<day<<setw(8)<<hours<<setw(4)<<minutes<<setw(4)<<seconds;
	//outStream<<blahblah... not finished yet...

	outStream<<setw(12)<<setprecision(6)<<cloudBottomIndex<<setw(12)<<setprecision(4)<<cloudBottomHeight<<endl;
	
	return SUCCEED;
}
int OneLine::WriteMixLayerTimeSerie(ostream &outStream)
{
	if(bIsSigma)
	{
		cout<<"Error : Can't get mixlayer height from sigmaA line"<<endl;
		return FAILED;
	}
	if(!outStream)
	{
		cout<<"Error : Invalid outStream for Mix Layer Serie..."<<endl;
		return FAILED;
	}
	int MLIndex=GetMixlayerIndex(ini.mixlayerDetectThreshold,ini.mixlayerDetectThreshold2, ini.mixlayerDetectThreshold3);
	float MLHeight=-999;
	if (MLIndex>=FIRSTDATAINDEX && MLIndex<binsNum)
		MLHeight=IndexToHeight(MLIndex);


	outStream<<setw(4)<<year<<setw(4)<<month<<setw(4)<<day<<setw(8)<<hours<<setw(4)<<minutes<<setw(4)<<seconds;
	//outStream<<blahblah... not finished yet...
	outStream<<setw(12)<<setprecision(6)<<MLIndex<<setw(12)<<setprecision(4)<<MLHeight<<endl;
	
	return SUCCEED;
}


